package graphiceditor4robot.more.fsm;

import java.io.File;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Pattern;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.Path;

import behaviourdiagram.Behaviour;
import behaviourdiagram.BehaviourInput;
import behaviourdiagram.BehaviourOutput;
import behaviourdiagram.util.BehaviourdiagramSerializer;
import graphiceditor4robot.plugin.Activator;
import fsm.FSM;
import fsm.Transition;

public class FSMChecker {

	private Behaviour behaviour;

	private FSM fsm;
	
	private ArrayList<String> warnings;
	
	private ArrayList<String> errors;

	private IFile fsmFile;

	private IFile behaviourFile;

	public FSMChecker (Behaviour behaviour, IFile behaviourFile) {
		this.behaviour = behaviour;
		this.warnings = new ArrayList<String>();
		this.errors = new ArrayList<String>();
		loadFSM(behaviourFile);
	}
	
	public FSMChecker(Behaviour behaviour, FSM fsm) {
		this.behaviour = behaviour;
		this.fsm = fsm;
		this.warnings = new ArrayList<String>();
		this.errors = new ArrayList<String>();
	}

	public Behaviour getBehaviour() {
		return behaviour;
	}

	public void setBehaviour(Behaviour behaviour) {
		this.behaviour = behaviour;
	}

	public FSM getFsm() {
		return fsm;
	}

	public void setFsm(FSM fsm) {
		this.fsm = fsm;
	}
	
	public ArrayList<String> getLastValidationErrors () {
		return errors;
	}

	public ArrayList<String> getLastValidationWarnings () {
		return warnings;
	}

	private void loadFSM (IFile behaviourFile) {
		Activator activator = Activator.getDefault();
		IFile fsmFile = behaviourFile.getParent().getFile(Path.fromPortableString(behaviour.getName() + ".fsm.xmi"));
		File file = new File(fsmFile.getLocation().toOSString());
		if (!file.exists()) {
			String message = MessageFormat.format(activator.getResourceBundle().getString("FSMNotFound"), behaviour.getName());
			activator.reportError(behaviourFile, 0, message);
			activator.showMessage(message);
			return;
		}
		this.fsm = BehaviourdiagramSerializer.loadFSM(file);
		this.fsmFile = fsmFile;
		this.behaviourFile = behaviourFile;
	}
	
	public void check() {
		
		
		Activator activator = Activator.getDefault();
		activator.removeMarkers(behaviourFile);
		activator.removeMarkers(fsmFile);
		
		if (!checkFSM()) {
			activator.showMessage(activator.getResourceBundle().getString("FSMValidationFailed"));
		} else {
			if (warnings.size() > 0) {
				String message = activator.getResourceBundle().getString("FSMValidationWithWarnings");
				activator.showMessage(MessageFormat.format(message, warnings.size()));
			} else {
				activator.showMessage(activator.getResourceBundle().getString("FSMValidationSuccess"));
			}
		}
		for (String error : getLastValidationErrors()) {
			activator.reportError(fsmFile, 0, error);
		}
		for (String warning : getLastValidationWarnings()){
			activator.reportWarning(fsmFile, 0, warning);
		}
	}
	
	private boolean checkFSM() {
		this.warnings = new ArrayList<String>();
		this.errors = new ArrayList<String>();
		ArrayList<String> inputs = new ArrayList<String>();
		int i = 0;
		for (BehaviourInput input : behaviour.getInputs()) {
			if (input.getName() == null) {
				warnings.add(Activator.getDefault().getResourceBundle().getString("AnonymousBehaviourInput"));
				continue;
			}
			if (input.getSensor() == null) {
				String message = Activator.getDefault().getResourceBundle().getString("BehaviourInputNotConnected");
				warnings.add(MessageFormat.format(message, input.getName()));
				continue;
			}
			
			inputs.add("$" + input.getName());
			i++;
		}
		for (BehaviourOutput output : behaviour.getOutputs()) {
			if (output.getName() == null) {
				warnings.add(Activator.getDefault().getResourceBundle().getString("AnonymousBehaviourOutput"));
				continue;
			}
			if (output.getActuator() == null) {
				String message = Activator.getDefault().getResourceBundle().getString("BehaviourOutputNotConnected");
				warnings.add(MessageFormat.format(message, output.getName()));
				continue;
			}
			
		}
		boolean valid = true;
		for (Transition transition : fsm.getOwnedTransitions()) {
			String condition = transition.getCondition();
			for (String element : extractVariables(condition)) {
				if (!element.isEmpty() && !inputs.contains(element)) {
					String message = Activator.getDefault().getResourceBundle().getString("BehaviourOutputNotConnected");
					errors.add(MessageFormat.format(message, element, condition));
					valid = false;
				}
			}
		}
		return valid;
	}

	private ArrayList<String> extractVariables(String expression) {
		String regex = "<|>|\\+|-|=|\\||&|!|([-+]?\\d+(\\.\\d+)?)";
		Pattern p = Pattern.compile(regex);
		String [] matches = p.split(expression.replaceAll(" ", ""));
		
		return new ArrayList<String>(Arrays.asList(matches));
	}
	
	public void loadFile (IFile eclipseFile) {
		
		

	}
}
